package com.fx.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.DatePrinter;
import com.fx.entity.*;
import com.fx.mapper.*;
import com.fx.service.OrderInfoService;
import com.fx.service.UserCartService;
import com.fx.service.WxPayConfigService;
import com.fx.util.IdWorker;
import com.fx.util.MD5Util;
import com.fx.util.WxUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import me.chanjar.weixin.common.util.DataUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;


@Service
public class OrderInfoServiceImpl implements OrderInfoService {
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private UserCartService userCartService;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private UserAddressMapper userAddressMapper;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private WxPayConfigService wxPayConfigService;
    @Autowired
    private GoodsInfoMapper goodsInfoMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private ChangeRecordMapper changeRecordMapper;
    @Autowired
    private SysConfigMapper sysConfigMapper;

    @Override
    public OrderInfo getById(String flId) {
        return orderInfoMapper.getById(flId);
    }

    @Override
    public List<OrderInfo> getList(Map<String, Object> map) {
        return orderInfoMapper.queryList(map);
    }

    @Override
    public int getCount(Map<String, Object> map) {
        return orderInfoMapper.queryCount(map);
    }

    @Override
    public int save(OrderInfo orderInfo) {
        orderInfo.setFlId(String.valueOf(idWorker.nextId()));
        orderInfo.setFlCreatedTime(DateUtil.now());
        return orderInfoMapper.save(orderInfo);
    }

    @Override
    public int updateById(OrderInfo orderInfo) {
        return orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public int remove(String flId) {
        return orderInfoMapper.remove(flId);
    }

    @Override
    public int batchRemove(String[] flIds) {
        return orderInfoMapper.batchRemove(flIds);
    }

    @Override
    public List<OrderInfo> getOrderByUserId(String userId) {
        return orderInfoMapper.queryOrderByUserId(userId);
    }

    @Override
    public OrderInfo generalOrder(String userId, String addressId) {
        UserAddress address = userAddressMapper.getById(addressId);
        List<UserCart> userCartList = userCartService.getCartByUserId(userId);
        String id = String.valueOf(idWorker.nextId());
        Double totalPrice = 0.0;
        for (UserCart userCart : userCartList) {
            OrderItem orderItem = new OrderItem();
            orderItem.setFlId(String.valueOf(idWorker.nextId()));
            orderItem.setFlCreatedTime(DateUtil.now());
            orderItem.setFlGoodsId(userCart.getFlGoodsId());
            orderItem.setFlName(userCart.getFlName());
            orderItem.setFlPrice(userCart.getFlPrice());
            orderItem.setFlQuantity(userCart.getFlQuantity());
            orderItem.setFlThumbnail(userCart.getFlThumbnail());
            orderItem.setFlSubtotal(userCart.getFlSubtotal());
            orderItem.setFlOrgPrice(userCart.getFlOriginPrice());
            orderItem.setFlOrderId(id);
            totalPrice += userCart.getFlSubtotal().doubleValue();
            orderItemMapper.save(orderItem);
            userCartService.remove(userCart.getFlId());
        }
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setFlId(id);
        orderInfo.setFlCreatedTime(DateUtil.now());
        orderInfo.setFlUserId(userId);
        orderInfo.setFlOrderTotal(BigDecimal.valueOf(totalPrice));
        orderInfo.setFlPayStatus(0);
        orderInfo.setFlStatus(0);
        orderInfo.setFlReceiverName(address.getFlName());
        orderInfo.setFlReceiverPhone(address.getFlPhone());
        orderInfo.setFlReceiverName(address.getFlName());
        orderInfo.setFlReceiverAddr(address.getFlProvince() + "_" + address.getFlCity() + "_" + address.getFlArea() + "_" + address.getFlDetailAddr());
         orderInfoMapper.save(orderInfo);
        return orderInfo;
    }

    @Override
    public Map<String,String> orderPayment(String orderId, String clientIp, String prefixUrl) throws Exception {
        Map<String, Object> param = new HashMap<String, Object>();
        String orderNo = "ORDER_NO" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSSS");
        param.put("flIsEnable", 1);
        WxPayConfig wxPayConfig = wxPayConfigService.getList(param).get(0);
        OrderInfo orderInfo = orderInfoMapper.getById(orderId);
        UserInfo userInfo = userInfoMapper.getById(orderInfo.getFlUserId());
        param.clear();
        param.put("flOrderId", orderId);
        List<OrderItem> orderItemList = orderItemMapper.queryList(param);
        StringBuilder body = new StringBuilder();
        for (OrderItem orderItem : orderItemList) {
            body.append(orderItem.getFlName() + ",");
        }
        String realBody = body.substring(0, body.length() - 1);
        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = WxPayUnifiedOrderRequest.newBuilder().build();
        wxPayUnifiedOrderRequest.setAppid(wxPayConfig.getFlAppId());
        wxPayUnifiedOrderRequest.setMchId(wxPayConfig.getFlMchId());
        wxPayUnifiedOrderRequest.setOutTradeNo(orderNo);
        wxPayUnifiedOrderRequest.setBody(realBody);
        wxPayUnifiedOrderRequest.setDetail("9090分销网络");
        wxPayUnifiedOrderRequest.setTotalFee((int)orderInfo.getFlOrderTotal().doubleValue()*100);
        wxPayUnifiedOrderRequest.setSpbillCreateIp(clientIp);
        wxPayUnifiedOrderRequest.setTimeStart(DateUtil.format(new Date(),"yyyyMMddHHmmss"));
        wxPayUnifiedOrderRequest.setTimeExpire(DateUtil.format(new Date(new Date().getTime()+360000), "yyyyMMddHHmmss"));
        wxPayUnifiedOrderRequest.setSignType("MD5");
        wxPayUnifiedOrderRequest.setNotifyUrl(prefixUrl + wxPayConfig.getFlCallbackUrl());
        wxPayUnifiedOrderRequest.setTradeType("JSAPI");
        wxPayUnifiedOrderRequest.setOpenid(userInfo.getFlOpenId());
        WxPayUnifiedOrderResult orderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
        orderInfo.setFlOrderNo(orderNo);
        orderInfoMapper.updateById(orderInfo);
        param.clear();
        Map<String,String> wxJsPay = new HashMap<String,String>();
        wxJsPay.put("appId",orderResult.getAppid());
        wxJsPay.put("timeStamp",String.valueOf(System.currentTimeMillis()/1000));
        wxJsPay.put("nonceStr", UUID.randomUUID().toString().replaceAll("-",""));
        wxJsPay.put("package","prepay_id="+orderResult.getPrepayId());
        wxJsPay.put("signType","MD5");
        String stringA = WxUtil.formatUrlMap(wxJsPay,false,false);
        stringA = stringA+"&key="+wxPayConfig.getFlMchKey();
        wxJsPay.put("sign", MD5Util.digestHex(stringA).toUpperCase());
        return wxJsPay;
    }

    @Override
    public WxPayRefundResult refund(String orderId) throws WxPayException {
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("flIsEnable", 1);
        WxPayConfig wxPayConfig = wxPayConfigService.getList(param).get(0);
        WxPayRefundRequest refundRequest = new WxPayRefundRequest();
        OrderInfo orderInfo = orderInfoMapper.getById(orderId);
        WxPayRefundResult refundResult = new WxPayRefundResult();
        String refundNo = "REFUND_NO" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSSS");
        if (orderInfo != null && wxPayConfig != null) {
            String orderNo = orderInfo.getFlOrderNo();
            refundRequest.setAppid(wxPayConfig.getFlAppId());
            refundRequest.setMchId(wxPayConfig.getFlMchId());
            refundRequest.setOutTradeNo(orderNo);
            refundRequest.setOutRefundNo(refundNo);
            orderInfo.setFlRefundNo(refundNo);
            int refundFee = (int) (orderInfo.getFlOrderTotal().doubleValue() * 100);
            refundRequest.setTotalFee(refundFee);
            refundRequest.setRefundDesc("用户申请退款!");
            refundResult = wxPayService.refund(refundRequest);
            if ("SUCCESS".equalsIgnoreCase(refundResult.getResultCode())) {
                orderInfo.setFlStatus(6);
            }
            orderInfo.setFlStatus(5);
            orderInfo.setFlRefundReason(refundResult.getErrCodeDes());
            orderInfoMapper.updateById(orderInfo);
            return refundResult;
        }

        return refundResult;
    }

    @Override
    public WxPayNotifyResponse payResultNotify(WxPayOrderNotifyResult notifyResult) {
        String returnCode = notifyResult.getReturnCode();
        String resultCode = notifyResult.getResultCode();
        WxPayNotifyResponse response = new WxPayNotifyResponse();
        if ("SUCCESS".equalsIgnoreCase(returnCode) && "SUCCESS".equalsIgnoreCase(resultCode)) {
            String orderNo = notifyResult.getOutTradeNo();
            OrderInfo orderInfo = orderInfoMapper.queryOrderByOrderNo(orderNo);
            orderInfo.setFlStatus(1);
            orderInfo.setFlPayStatus(1);
            orderInfo.setFlPayTime(notifyResult.getTimeEnd());
            orderInfoMapper.updateById(orderInfo);
            UserInfo userInfo = userInfoMapper.getById(orderInfo.getFlUserId());
            String cstId = userInfo.getFlCstId();
            Map<String, Object> param = new HashMap<String, Object>();
            SysConfig sysConfig = null;
            if ("-1".equalsIgnoreCase(cstId)) {
                param.put("flCstId", -1);
                sysConfig = sysConfigMapper.queryList(param).get(0);
            } else {
                param.put("flCstId", cstId);
                sysConfig = sysConfigMapper.queryList(param).get(0);
            }

            param.put("flUserId", userInfo.getFlId());
            param.put("flPayStatus", 1);
            List<OrderInfo> orderInfoList = orderInfoMapper.queryList(param);
            BigDecimal totalAmount = orderInfo.getFlOrderTotal();
            for (OrderInfo order : orderInfoList) {
                totalAmount = totalAmount.add(order.getFlOrderTotal());
            }
            BigDecimal minBuy = sysConfig.getFlMinBuy();
            if (totalAmount.doubleValue() > minBuy.doubleValue()) {
                userInfo.setFlIsDis(1);
                userInfoMapper.updateById(userInfo);
            }
            param.clear();
            param.put("flOrderId", orderInfo.getFlId());
            List<OrderItem> orderItemList = orderItemMapper.queryList(param);
            String goodsIds = null;
            for (OrderItem orderItem : orderItemList) {
                goodsIds += orderItem.getFlGoodsId() + ",";
            }
            calculateProfit(userInfo, goodsIds, sysConfig);
            response.setReturnCode("SUCCESS");
            response.setReturnMsg("OK");
        }
        return response;
    }

    /**
     * 方法名称：计算利润
     * 概要说明：计算利润
     *
     * @Ather EDZ
     * @Date 2018-6-26 11:05
     * @Param
     * @Return
     */
    private void calculateProfit(UserInfo userInfo, String goodsIds, SysConfig sysConfig) {
        String goodsIdArr[] = goodsIds.split(",");
        BigDecimal firstProfit = sysConfig.getFlFirstProfit();
        BigDecimal secondProfit = sysConfig.getFlSecondProfit();
        BigDecimal thirdProfit = sysConfig.getFlThirdProfit();
        int disProfitType = sysConfig.getFlType();
        UserInfo firstUser = null;
        UserInfo secondUser = null;
        UserInfo thirdUser = null;
        if (!"-1".equalsIgnoreCase(userInfo.getFlUpUser()) && !"".equalsIgnoreCase(userInfo.getFlUpUser())) {
            firstUser = userInfoMapper.getById(userInfo.getFlUpUser());
            if (firstUser != null) {
                String firstUp = firstUser.getFlUpUser();
                if (!"-1".equalsIgnoreCase(firstUp) && !"".equalsIgnoreCase(firstUp)) {
                    secondUser = userInfoMapper.getById(firstUp);
                    if (secondUser != null) {
                        String secondUp = secondUser.getFlUpUser();
                        if (!"-1".equalsIgnoreCase(secondUp) && !"".equalsIgnoreCase(secondUp)) {
                            thirdUser = userInfoMapper.getById(secondUp);
                        }
                    }
                }
            }
        }

        for (String goodsId : goodsIdArr) {
            GoodsInfo goodsInfo = goodsInfoMapper.getById(goodsId);
            Integer goodsIsDis = goodsInfo.getFlIsEnableGoodsDis();
            if (goodsIsDis == 1) {
                firstProfit = goodsInfo.getFlFirstProfit();
                secondProfit = goodsInfo.getFlFirstProfit();
                thirdProfit = goodsInfo.getFlThirdProfit();
                disProfitType = goodsInfo.getFlType();
            }
            if (disProfitType == 0) {
                //百分百
                if (goodsInfo.getFlIsEnableGoodsDis() == 1) {
                    //商品分润
                    calculateProfit(firstUser, secondUser, thirdUser, firstProfit, secondProfit, thirdProfit, goodsInfo.getFlSalePrice(), disProfitType);
                } else if (sysConfig.getFlIsEnableDis() == 1) {
                    //平台/商户分润
                    calculateProfit(firstUser, secondUser, thirdUser, firstProfit, secondProfit, thirdProfit, goodsInfo.getFlSalePrice(), disProfitType);
                }
            } else if (disProfitType == 1) {
                //实际金额
                if (goodsInfo.getFlIsEnableGoodsDis() == 1) {
                    //商品分润
                    calculateProfit(firstUser, secondUser, thirdUser, firstProfit, secondProfit, thirdProfit, goodsInfo.getFlSalePrice(), disProfitType);
                } else if (sysConfig.getFlIsEnableDis() == 1) {
                    //平台/商户分润
                    calculateProfit(firstUser, secondUser, thirdUser, firstProfit, secondProfit, thirdProfit, goodsInfo.getFlSalePrice(), disProfitType);
                }
            }

        }

    }

    /**
     * 方法名称：计算会员利润
     * 概要说明：计算会员利润
     *
     * @Ather EDZ
     * @Date 2018-6-26 11:37
     * @Param [firstUser, secondUser, thirdUser, firstProfit, secondProfit, thirdProfit,price  type:0百分百1:实际值]
     * @Return void
     */
    private void calculateProfit(UserInfo firstUser, UserInfo secondUser, UserInfo thirdUser, BigDecimal firstProfit, BigDecimal secondProfit, BigDecimal thirdProfit, BigDecimal price, int type) {
        String userId = null;
        String reason = null;
        BigDecimal amount = null;
        if (firstUser != null && firstUser.getFlIsDis() == 1) {
            if (type == 0) {
                userId = firstUser.getFlId();
                reason = "一级分润";
                amount = price.multiply(firstProfit);
                saveRecord(userId, reason, amount);
            } else if (type == 1) {
                userId = firstUser.getFlId();
                reason = "一级分润";
                amount = price.add(firstProfit);
                saveRecord(userId, reason, amount);
            }
        }
        if (secondUser != null && secondUser.getFlIsDis() == 1) {
            if (type == 0) {
                userId = secondUser.getFlId();
                reason = "二级分润";
                amount = price.multiply(secondProfit);
                saveRecord(userId, reason, amount);
            } else if (type == 1) {
                userId = secondUser.getFlId();
                reason = "二级分润";
                amount = price.add(secondProfit);
                saveRecord(userId, reason, amount);
            }
        }
        if (thirdUser != null && thirdUser.getFlIsDis() == 1) {
            if (type == 0) {
                userId = thirdUser.getFlId();
                reason = "三级分润";
                amount = price.multiply(thirdProfit);
                saveRecord(userId, reason, amount);
            } else if (type == 1) {
                userId = thirdUser.getFlId();
                reason = "三级分润";
                amount = price.add(thirdProfit);
                saveRecord(userId, reason, amount);
            }
        }
    }

    private void saveRecord(String userId, String reason, BigDecimal amount) {
        ChangeRecord changeRecord = new ChangeRecord();
        changeRecord.setFlUserId(userId);
        changeRecord.setFlType(0);
        changeRecord.setFlStatus(1);
        changeRecord.setFlReason(reason);
        changeRecord.setFlChangeTime(DateUtil.now());
        changeRecord.setFlChangeNo(DateUtil.format(new Date(), "yyyyMMddHHmmssSSSS"));
        changeRecord.setFlChangeAmount(amount);
        changeRecordMapper.save(changeRecord);
    }
}
